<!doctype html>
<html>
    <head>
        <title>Test Grid</title>
        <style type="text/css">
            #myCan {
                border: thin black solid;
                width: 640;
                height: 800;
            }
        </style>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>        
        <script>
            var app = {};
        </script>
        <script>
        var Input = function(){
            var self = this;
            var map    = { 38: "U", 40: "D", 37: "L", 39: "R" };
            self.state = { U: false, D: false, L: false, R: false };            
            self.keydown = function(evnt){
                var mKey = map[evnt.which];
                if(mKey != "undefined"){
                    self.state[mKey] = true;
                }
            }
            
            self.keyup = function(evnt){                
                var mKey = map[evnt.which];
                if(mKey){
                    self.state[mKey] = false;
                }
            }
            
            $(document).keydown(self.keydown);
            $(document).keyup(self.keyup);
        }
        
        $(function(){app.input = new Input()});
        </script>
        <script>
            var MainLoop = function(){                
                var self = this;
                var tickTime = 10; //How many times to rerun through the game loop in MS
                
                // Constant function queue                 
                self.constantList = [];
                
                //List of functions to be run per tick as needed                 
                self.runQueue = [];
                /**
                 *The logic loop's interval ID
                 */
                var runnerHandle = null;
                self.logicLoop = function(){
                    $.each(self.constantList, function(index, handler){
                        try{
                            handler();
                        }catch(err){
                            console.debug(err);
                            self.stop();
                        }
                    });
                                
                    if(self.runQueue.length > 0){                    
                        var func = runQueue.shift();
                        func();
                    }    
                }
                
                self.start = function(){
                    runnerHandle = setInterval(self.logicLoop, tickTime);    
                }
                self.stop = function(){
                    clearInterval(runnerHandle);
                }
            };
            
            app.loop = new MainLoop();
            
            var simpleKeyMap = {"U":"statUP", "D":"statDOWN", "L":"statLEFT", "R":"statRIGHT" };
            var lastState = {};
            
            //
            app.loop.constantList.push(function(){
                    $.each(app.input.state, function(key, val){
                        
                        if(lastState[key] !== val){
                            var ElementID = "#" + simpleKeyMap[key];
                            //console.log("triggering ", ElementID);
                            //console.log(key +" " + val);
                            
                            $(ElementID).css({"backgroundColor": val ? "green" : "red"});                                    
                        }
                        
                                            
                        lastState[key] = val;
                    });
            });
        
            //$(function(){
            //    var ctx = document.getElementById("myCan").getContext("2d");            
            //    app.loop.start();
            //});
            
        </script>
        <script>
        /**
         *Attempted port of my 1996 lunar loader game from C/0x13H to JS/canvas
         *
         *@var 
         */
            var LunarLander = function(ctx, canHeight, canWidth){                
                var self = this;
                var intern = {};
                intern.ctx = ctx;
                intern.cHeight = canHeight;
                intern.cWidth = canWidth;
                
                
                self.xPos = canHeight/ 2;
                self.yPos = canWidth/ 2;
                
                self.showX = function() {};
                self.showY = function() {};
                self.showDeltaX = function() {};
                self.showDeltaY = function() {};
                
                intern.xVel = 0;
                intern.yVel = -1;
                
                var verticalThrust = 1.2;
                var horzThrust = .6;
                var gravity = .09;
                var terminalVelocity = 14;
                var maxTrustVelocity = -8;
                
                //How fast is too fast?
                var crashVelocity = 3.5;  //Anything below 3.5 is fuck all impossible
                
                
                intern.logic = function(){
                    var changed = true;
                    var dx = 0;
                    var dy = 0;
                    
                    
                    
                    
                    //Stage 1 - Verify/check inputs
                    if(app.input.state["L"]) dx -=  horzThrust;
                    if(app.input.state["R"]) dx +=  horzThrust;
                    if(app.input.state["U"]) dy -= verticalThrust;
                    if(app.input.state["D"]) dy += verticalThrust;
                    
                    //Boxes te delta's into  range -8...14
                    intern.yVel = Math.max(maxTrustVelocity, Math.min( terminalVelocity, intern.yVel  + gravity + dy));
                    intern.xVel = Math.max(maxTrustVelocity, Math.min( terminalVelocity, intern.xVel  + dx));
                    
                    
                    
                    
                    //Possible that counter forces will neutralize each other, for now that's fine
                    //if(dx != 0 || dy != 0) changed = true;
                    ;
                    
                    //TODO Add boundary checks
                    
                    self.xPos = Math.max(0, Math.min(intern.cHeight, self.xPos + intern.xVel));
                    //Crash tests
                    //If we're on the edge and our velocity is greater then 2 pixels a tick... bounce!
                    if(self.xPos == intern.cHeight){
                        if( Math.abs(intern.xVel) > 2){
                            intern.xVel = (intern.xVel * -1 ) / 2
                            
                        }else if(Math.abs(intern.xVel) < 2){
                            intern.xVel = 0;
                        }
                        
                    }
                    
                    self.yPos = Math.max(0, Math.min(intern.cWidth, self.yPos + intern.yVel));
                    if(self.yPos == intern.cWidth){
                        if(Math.abs(intern.yVel) > crashVelocity){
                            console.log("Damage % " + intern.yVel * 100 + " impact velocity was " + intern.yVel + " Pixesl/Sec" )
                            
                            intern.yVel = (intern.yVel * -1 ) / 2
                        }else if(Math.abs(intern.yVel) < crashVelocity){
                            console.log("Safe landing!");
                            app.loop.stop();
                            intern.yVel = 0; //Cut it!
                        }
                    }
                    
                    //Clean our x/y up a tad
                    self.xPos = Math.round(self.xPos)
                    self.yPos = Math.round(self.yPos)
                    
                    //Draw
                    if(changed){
                        ctx.clearRect(0,0, intern.cHeight, intern.cWidth);
                        ctx.beginPath();
                        ctx.arc(self.xPos, self.yPos, 5, 0, Math.PI*2, true);
                        ctx.fill();
                        self.showX(self.xPos);
                        self.showDeltaX(intern.xVel);
                        self.showDeltaY(intern.yVel);
                        self.showY(self.yPos);
                    }
                    
                }
                
                
                //Initialization logic
                self.initialize = function(){
                    ctx.arc(self.xPos, self.yPos, 5, 0, Math.PI*2, true);                
                    app.loop.constantList.push(intern.logic);
                    self.showX(self.xPos);
                    self.showY(self.yPos);
                }
            }
            $(function(){
                app.lunar = new LunarLander(document.getElementById("myCan").getContext("2d"), 800, 640);
                app.lunar.showX = function(val){ $("#xPOS").val(val); }
                app.lunar.showY = function(val){ $("#yPOS").val(val); }
                
                app.lunar.showDeltaX = function(val){ $("#xDELTA").val(val); }
                app.lunar.showDeltaY = function(val){ $("#yDELTA").val(val); }
                app.lunar.initialize();
                app.loop.start();
                });
        </script>
    </head>
    <body>
        
            <canvas height="640" width="800" id="myCan"> If you can see this, you're browser and probably your computer are inferior. </canvas>        
        <div style="float: right" >
            <h1>Status board</h1>
            <ul >
                <li><span id="statUP">Up</span></li>
                <li><span id="statDOWN">Down</span></li>
                <li><span id="statLEFT">Left</span></li>
                <li><span id="statRIGHT">Right</span></li>
                <li><Label>X:</Label><input id="xPOS"></li>
                <li><Label>Y:</Label><input id="yPOS"></li>
                <li><label>Delta X:<input id="xDELTA"></label></li>
                <li><label>Delta Y:<input id="yDELTA"></label></li>
            </ul>
        </div>
    </body>
</html>